package rules

import (
	"ddl_checker/internal/config"
	"fmt"
	"regexp"
	"strings"
)

// SecurityValidator 安全检查器 - 检查DDL中的安全风险
type SecurityValidator struct {
	*BaseAPIChecker
}

// NewSecurityValidator 创建安全检查器
func NewSecurityValidator() *SecurityValidator {
	config := APICheckerConfig{
		Enabled:  config.GetBool("SECURITY_VALIDATOR_ENABLED", false),
		Timeout:  10,
		Endpoint: "",
		ApiKey:   "",
	}
	return &SecurityValidator{
		BaseAPIChecker: NewBaseAPIChecker("安全检查器", config),
	}
}

// NewSecurityValidatorEnabled 创建带启用状态的安全检查器
func NewSecurityValidatorEnabled(enabled bool) *SecurityValidator {
	config := APICheckerConfig{
		Enabled:  enabled,
		Timeout:  10,
		Endpoint: "",
		ApiKey:   "",
	}
	return &SecurityValidator{
		BaseAPIChecker: NewBaseAPIChecker("安全检查器", config),
	}
}

// NewSecurityValidatorWithConfig 创建带配置的安全检查器
func NewSecurityValidatorWithConfig(config ValidatorConfig) *SecurityValidator {
	checkerConfig := APICheckerConfig{
		Enabled: config.Enabled,
		Timeout: 10,
	}

	// 从设置中读取超时时间
	if timeout, ok := config.Settings["timeout"].(float64); ok {
		checkerConfig.Timeout = int(timeout)
	}

	return &SecurityValidator{
		BaseAPIChecker: NewBaseAPICheckerWithSettings("安全检查器", checkerConfig, config.Settings),
	}
}

// Validate 执行安全检查
func (v *SecurityValidator) Validate(data DDLCheckData) APIResult {
	result := APIResult{
		Conclusion: APIConclusionPass,
		Details:    []string{"### 安全检查"},
	}

	if strings.TrimSpace(data.Script) == "" {
		result.Conclusion = APIConclusionFail
		result.Details = append(result.Details, "❌ 未提供DDL脚本")
		return result
	}

	// 危险操作检测
	dangerousPatterns := map[string]string{
		`(?i)\bDROP\s+DATABASE\b`:                    "删除数据库",
		`(?i)\bDROP\s+SCHEMA\b`:                      "删除模式",
		`(?i)\bTRUNCATE\s+TABLE\b`:                   "清空表数据",
		`(?i)\bDELETE\s+FROM\s+\w+\s+WHERE\s+1=1\b`:  "删除所有数据",
		`(?i)\bUPDATE\s+\w+\s+SET\s+.*WHERE\s+1=1\b`: "更新所有数据",
	}

	warningPatterns := map[string]string{
		`(?i)\bDROP\s+TABLE\b`:              "删除表",
		`(?i)\bALTER\s+TABLE\b`:             "修改表结构",
		`(?i)\bGRANT\s+ALL\s+PRIVILEGES\b`:  "授予所有权限",
		`(?i)\bREVOKE\s+ALL\s+PRIVILEGES\b`: "撤销所有权限",
	}

	dangerCount := 0
	warningCount := 0

	// 检查危险模式
	for pattern, description := range dangerousPatterns {
		re := regexp.MustCompile(pattern)
		if re.MatchString(data.Script) {
			dangerCount++
			result.Details = append(result.Details, fmt.Sprintf("🚨 检测到危险操作: %s", description))
		}
	}

	// 检查警告模式
	for pattern, description := range warningPatterns {
		re := regexp.MustCompile(pattern)
		if re.MatchString(data.Script) {
			warningCount++
			result.Details = append(result.Details, fmt.Sprintf("⚠️  检测到需要谨慎的操作: %s", description))
		}
	}

	// 检查SQL注入风险
	if v.hasSQLInjectionRisk(data.Script) {
		warningCount++
		result.Details = append(result.Details, "⚠️  可能存在SQL注入风险，建议使用参数化查询")
	}

	// 检查权限过度
	if v.hasExcessivePrivileges(data.Script) {
		warningCount++
		result.Details = append(result.Details, "⚠️  检测到过度权限操作")
	}

	// 确定结论
	if dangerCount > 0 {
		result.Conclusion = APIConclusionFail
		result.Details = append(result.Details, fmt.Sprintf("❌ 发现%d个高风险操作", dangerCount))
	} else if warningCount > 0 {
		result.Conclusion = APIConclusionWarning
		result.Details = append(result.Details, fmt.Sprintf("⚠️  发现%d个需要注意的风险", warningCount))
	} else {
		result.Details = append(result.Details, "✅ 安全检查通过")
	}

	return result
}

// hasSQLInjectionRisk 检查是否存在SQL注入风险
func (v *SecurityValidator) hasSQLInjectionRisk(script string) bool {
	// 检查是否包含字符串拼接和动态SQL
	riskyPatterns := []string{
		`(?i)\+\s*['"]\s*\w+\s*['"]`,  // 字符串拼接
		`(?i)CONCAT\s*\([^)]*\)`,      // CONCAT函数
		`(?i)\bEXEC\b`,                // EXEC语句
		`(?i)\bEXECUTE\s+IMMEDIATE\b`, // EXECUTE IMMEDIATE
	}

	for _, pattern := range riskyPatterns {
		if matched, _ := regexp.MatchString(pattern, script); matched {
			return true
		}
	}
	return false
}

// hasExcessivePrivileges 检查权限过度
func (v *SecurityValidator) hasExcessivePrivileges(script string) bool {
	privilegePatterns := []string{
		`(?i)\bGRANT\s+ALL\b`,
		`(?i)\bGRANT\s+DBA\b`,
		`(?i)\bGRANT\s+SYSADMIN\b`,
		`(?i)\bWITH\s+GRANT\s+OPTION\b`,
	}

	for _, pattern := range privilegePatterns {
		if matched, _ := regexp.MatchString(pattern, script); matched {
			return true
		}
	}
	return false
}
